package framework.mvc;

import bank.account.AccountFactory;
import bank.mvc.HeaderUtils;
import framework.Utils;
import framework.account.IAccount;
import framework.customer.ICustomer;
import framework.factory.customer.CustomerFactory;
import framework.mvc.header.AccountTableValue;
import framework.mvc.header.CustomerTableValue;

import javax.swing.*;
import java.util.*;


public class Finco {
    private List<Map<String, String>> tableRows;
    private Set<ICustomer> customers;
    private static Finco instance;

    public static Finco getInstance(){
        if(instance==null)
            instance=new Finco();
        return instance;
    }

    private Finco() {
        tableRows = new ArrayList<Map<String, String>>();
        customers = new HashSet<ICustomer>();
    }

    public void addCompanyAccunt(Map<String, String> cusMap){
        ICustomer customer =  createCustomer(cusMap);
        IAccount acc = AccountFactory.createAccount(cusMap.get("type"), cusMap.get("ccNumber"));
        customer.addAccount(acc);
        cusMap.put("amount", String.valueOf(acc.getBalance()));
        cusMap.put("ch/s", acc.getType());
        FincoContext.getView().getViewModel().addRow(Utils.map2row(HeaderUtils.getHeaderValue(), cusMap));
        addRow(cusMap);
        FincoContext.getView().unselectRow();
    }

    public void addPersonAccunt(Map<String, String> cusMap){
        ICustomer customer = FincoContext.getFinco().createCustomer(cusMap);
        IAccount acc = AccountFactory.createAccount(cusMap.get("type"), cusMap.get("ccNumber"));
        customer.addAccount(acc);
        cusMap.put("amount", String.valueOf(acc.getBalance()));
        cusMap.put("ch/s", acc.getType());
        FincoContext.getView().getViewModel().addRow(Utils.map2row(HeaderUtils.getHeaderValue(), cusMap));
        FincoContext.getFinco().addRow(cusMap);
        FincoContext.getView().unselectRow();
    }

    public ICustomer getCustomer(Map<String, String> map) {
        if (!FincoContext.getFinco().isExist(map.get("name"))) {
            ICustomer customer = new CustomerFactory().createCustomer(map);
            FincoContext.getFinco().addCustomer(customer);
            return customer;
        } else
            return FincoContext.getFinco().getCustomerByName(map.get("name"));
    }


    public ICustomer createCustomer(Map<String, String> map) {
        if (!isCustomerExist(map.get("name"))) {
            ICustomer customer = new CustomerFactory().createCustomer(map);
            addCustomer(customer);
            return customer;
        } else
            return getCustomerByName(map.get("name"));
    }

    public IAccount getAccount(String number) {
        for (ICustomer customer : customers) {
            IAccount account = customer.getAccount(number);
            if (account != null)
                return account;
        }
        return null;
    }

    public boolean isCustomerExist(String name) {
        for (ICustomer customer : customers) {
            if (customer.getName().equals(name))
                return true;
        }
        return false;
    }

    public ICustomer getCustomerByName(String name) {
        for (ICustomer customer : customers) {
            if (customer.getName().equals(name))
                return customer;
        }
        return null;
    }

    public IAccount findAccount(String number) {
        for (ICustomer customer : customers) {
            IAccount account = customer.getAccount(number);
            if (account != null)
                return account;
        }
        return null;
    }

    public void addCustomer(ICustomer customer) {
        customers.add(customer);
    }

    public boolean isExist(String name) {
        for (ICustomer customer : customers) {
            if (customer.getName().equals(name))
                return true;
        }
        return false;
    }

    public void addRow(Map<String, String> map) {
        tableRows.add(map);
    }

    public IAccount getSelectedAccount(Integer selectedIndex) {
        if (tableRows.size() < selectedIndex - 1)
            return null;
        String number = tableRows.get(selectedIndex).get("ccNumber");
        return findAccount(number);
    }

    public void refresh() {
        tableRows.clear();
        for (ICustomer customer : customers) {
            for (IAccount account : customer.getAccounts()) {
                Map<String, String> map = new HashMap<String, String>();
                new CustomerTableValue().setHeader(customer, map);
                new AccountTableValue().setHeader(account, map);
                tableRows.add(map);
            }
        }
    }

    public List<IAccount> getAccounts() {
        List<IAccount> list = new ArrayList<IAccount>();
        for (ICustomer customer : customers) {
            for (IAccount account : customer.getAccounts()) {
                list.add(account);
            }
        }
        return list;
    }


    public Map<String, String> getAccountData(String number) {
        for (Map<String, String> cusMap : tableRows) {
            if (cusMap.get("ccNumber").equals(number))
                return cusMap;
        }
        return null;
    }

    static public void main(String args[]) {
        try {

            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

            AFincoView defaultView = new AFincoView() {
                @Override
                protected String getAppTitle() {
                    return "Default Application";
                }

                @Override
                protected String getCreditReifiedName() {
                    return "";
                }

                @Override
                protected String getDebtReifiedName() {
                    return "";
                }

                @Override
                protected String[] getTableHeaders() {
                    return new String[0];
                }

                @Override
                protected void addButtons(Box box) {
                    box.add(new JTextField("This is default framework application"));
                }
            };
            //DI
            FincoContext.injectView(defaultView);

            //IoC
            defaultView.setVisible(true);
        } catch (Throwable t) {
            t.printStackTrace();
            System.exit(1);
        }
    }
}